package consensus

import (
	"github.com/looplab/fsm"
	"gopkg.in/oleiade/lane.v1"
	"github.com/spf13/viper"
	"time"
	"myPaxos/consensus/timers"
)

type Status struct {
	seqNo   int64
	view    int64
	primary int
}

type ReqInfo struct {
	seqNo   int64
	view    int64
}

type Proposer struct {
	ID          int
	checkPoints []*Status
	current     *Status
	cacheReqs   *lane.Deque // when the view-change occur, this queue is used to store the unhandled reqs in backups
	backupReqs  []int64
	fsm         *fsm.FSM
	timerConfig map[string]time.Duration
}

func NewProposer(id int, viper *viper.Viper) *Proposer {
	prop := &Proposer{
		ID:          id,
		checkPoints: make([]*Status, 0),
		cacheReqs:   lane.NewDeque(),
		backupReqs:  make([]int64, 0),
		timerConfig: make(map[string]time.Duration),
	}
	prop.current = &Status{
		view:   int64(0),
		seqNo:  int64(0),
		primary: 0,
	}
	prop.fsm = fsm.NewFSM(
		"NewProp",
		fsm.Events{
			{Name: "Start", Src: []string{"New"}, Dst: "viewChange"},
			{Name: "FinishVC", Src: []string{"ViewChange"}, Dst: "working"},
			{Name: "ViewChange", Src: []string{"working"}, Dst: "viewChange"},
		},
		fsm.Callbacks{},
	)

	if m,ok := viper.Get("consensus.viewChange").(map[string]time.Duration); ok {
		for k,v := range m {
			prop.timerConfig[k] = v
		}
	} else {
		panic("read config error")
	}
	return prop
}

func (proposer *Proposer) Start() {
	proposer.fsm.Event("Start")
	startBase := proposer.timerConfig["startBase"]
	informer, pause := timers.MakeTimerInformers()
	timers.GetVCStartTImer(startBase, informer, pause)
	// listen timer channels and start timer
}
